package com.nosnow.gmall.list.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.nosnow.gmall.bean.SkuLsInfo;
import com.nosnow.gmall.bean.SkuLsParams;
import com.nosnow.gmall.bean.SkuLsResult;
import com.nosnow.gmall.config.RedisUtil;
import com.nosnow.gmall.service.ListService;
import io.searchbox.client.JestClient;
import io.searchbox.core.*;
import io.searchbox.core.search.aggregation.MetricAggregation;
import io.searchbox.core.search.aggregation.TermsAggregation;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 保存sku数据的业务实现类
 */

@Service
public class ListServiceImpl implements ListService {

    @Autowired
    private JestClient jestClient;

    @Autowired
    private RedisUtil redisUtil;


    public static final String index_name_gmall ="gmall";

    public static final String type_name_gmall="SkuInfo";




    /**
     * 测试方法
     * @throws IOException
     */
    @Test
    public void testEs() throws IOException {

        // 定义查询的sql
        String queryStr = "{\n" +
                "  \"query\": {\n" +
                "    \"term\": {\n" +
                "      \"actorList.name\": \"张译\"\n" +
                "    }\n" +
                "  }\n" +
                "}";

        Search search = new Search.Builder(queryStr).addIndex("movies_index_chn").addType("movies_type_chn").build();

        SearchResult result = jestClient.execute(search);

        List<SearchResult.Hit<HashMap, Void>> hits = result.getHits(HashMap.class);
        for (SearchResult.Hit<HashMap, Void> hit : hits) {
            HashMap source = hit.source;
            System.err.println("source = " + source);

        }
    }

    @Override
    public void saveSkuLsInfo(SkuLsInfo skuLsInfo) {
        Index index = new Index.Builder(skuLsInfo).index(index_name_gmall).type(type_name_gmall).id(skuLsInfo.getId()).build();
        try {
            jestClient.execute(index);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String makeQueryStringForSearch(SkuLsParams skuLsParams) {

        SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if(skuLsParams.getKeyword() != null) {

            // 关键词
            MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("skuName",skuLsParams.getKeyword());
            boolQueryBuilder.must(matchQueryBuilder);

            // 高亮
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("skuName");
            highlightBuilder.preTags("<span style='color:red'>");
            highlightBuilder.postTags("</span>");
            searchSourceBuilder.highlight(highlightBuilder);

            // 聚合
            TermsBuilder groupby_attr = AggregationBuilders.terms("groupby_attr").field("skuAttrValueList.valueId");
            searchSourceBuilder.aggregation(groupby_attr);
        }

        // 三级分类过滤
        if(skuLsParams.getCatalog3Id() != null) {
            QueryBuilder termQueryBuilder=new TermQueryBuilder("catalog3Id",skuLsParams.getCatalog3Id());
            boolQueryBuilder.filter(termQueryBuilder);

        }

        // 平台属性过滤
        if(skuLsParams.getValueId() != null && skuLsParams.getValueId().length >= 0) {
            for(int i = 0; i < skuLsParams.getValueId().length; i++) {
                String valueId = skuLsParams.getValueId()[i];
                QueryBuilder termQueryBuilder = new TermsQueryBuilder("skuAttrValueList.valueId",valueId);
                boolQueryBuilder.filter(termQueryBuilder);
            }
        }

        // 分页
        searchSourceBuilder.query(boolQueryBuilder);
        int from = (skuLsParams.getPageNo() - 1) * skuLsParams.getPageSize();
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(skuLsParams.getPageSize());

        // 排序
        searchSourceBuilder.sort("hotScore", SortOrder.DESC);


        String query = searchSourceBuilder.toString();
        System.err.println("query = " + query);

        return query;
    }

    @Override
    public SkuLsResult search(SkuLsParams skuLsParams) {
        String query = makeQueryStringForSearch(skuLsParams);
        Search search = new Search.Builder(query).addIndex(index_name_gmall).addType(type_name_gmall).build();
        SearchResult searchResult = null;
        try {
            searchResult = jestClient.execute(search);
        } catch (Exception e){
            e.printStackTrace();
        }
        SkuLsResult skuLsResult = makeResultForSearch(skuLsParams, searchResult);

        return skuLsResult;
    }

    @Override
    public void incrHotScore(String skuId) {
        Jedis jedis = redisUtil.getJedis();
        Double hotScore = jedis.zincrby("hotScore", 1, skuId);
        if(hotScore % 100 == 0) {
            updateHotScore(skuId, hotScore);
        }
    }

    private SkuLsResult makeResultForSearch(SkuLsParams skuLsParams,SearchResult searchResult) {
        SkuLsResult skuLsResult = new SkuLsResult();
        List<SkuLsInfo> skuLsInfoList = new ArrayList<>(skuLsParams.getPageSize());

        // 获取sku列表
        List<SearchResult.Hit<SkuLsInfo, Void>> hits = searchResult.getHits(SkuLsInfo.class);
        for(SearchResult.Hit<SkuLsInfo, Void> hit : hits) {
            SkuLsInfo skuLsInfo = hit.source;
            if(hit.highlight != null && hit.highlight.size() > 0) {
                List<String> list = hit.highlight.get("skuName");
                // 把带有高亮标签的字符串替换skuName
                String skuNameHl = list.get(0);
                skuLsInfo.setSkuName(skuNameHl);
            }
            skuLsInfoList.add(skuLsInfo);
        }
        skuLsResult.setSkuLsInfoList(skuLsInfoList);
        skuLsResult.setTotal(searchResult.getTotal());

        //取记录个数并计算出总页数
        long totalPage = (searchResult.getTotal() + skuLsParams.getPageSize() -1) / skuLsParams.getPageSize();
        skuLsResult.setTotalPages(  totalPage);

        //取出涉及的属性值id
        List<String> attrValueIdList = new ArrayList<>();
        MetricAggregation aggregations = searchResult.getAggregations();
        TermsAggregation groupby_attr = aggregations.getTermsAggregation("groupby_attr");
        if(groupby_attr != null){
            List<TermsAggregation.Entry> buckets = groupby_attr.getBuckets();
            for (TermsAggregation.Entry bucket : buckets) {
                attrValueIdList.add( bucket.getKey()) ;
            }
            skuLsResult.setValueIdList(attrValueIdList);
        }

        return skuLsResult;
    }

    private void updateHotScore(String skuId, Double hotScore) {

        String updateJson = "{\n" + " \"doc\":{\n" + " \"hotScore\":\""+hotScore+"\"\n"+ "}\n"+ "}";
        Update update = new Update.Builder(updateJson).index(index_name_gmall).type(type_name_gmall).id(skuId).build();
        try {
            jestClient.execute(update);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
